package com.keqiang.chart.utils

import android.graphics.Paint
import android.graphics.Path
import android.graphics.PathMeasure
import android.graphics.RectF
import android.text.TextPaint

/**
 * 对象池,目前由于所有执行都在主线程，因此不加线程同步
 *
 * @author Created by wanggaowan on 2022/8/23 16:02
 */
object ObjectPool {
    private val pathPool: MutableList<Path> = mutableListOf()
    private val pathMeasurePool: MutableList<PathMeasure> = mutableListOf()
    private val rectFPool: MutableList<RectF> = mutableListOf()
    private val floatArrayPool: MutableList<FloatArray> = mutableListOf()
    private val paintPool: MutableList<Paint> = mutableListOf()
    private var isRelease = true

    @JvmStatic
    fun obtainPath(): Path {
        return if (pathPool.isEmpty()) {
            Path()
        } else {
            val obj = pathPool[pathPool.size - 1]
            pathPool.removeAt(pathPool.size - 1)
            obj
        }
    }

    @JvmStatic
    fun obtainPathMeasure(): PathMeasure {
        return if (pathMeasurePool.isEmpty()) {
            PathMeasure()
        } else {
            val obj = pathMeasurePool[pathMeasurePool.size - 1]
            pathMeasurePool.removeAt(pathMeasurePool.size - 1)
            obj
        }
    }

    @JvmStatic
    fun obtainRectF(): RectF {
        return if (rectFPool.isEmpty()) {
            RectF()
        } else {
            val obj = rectFPool[rectFPool.size - 1]
            rectFPool.removeAt(rectFPool.size - 1)
            obj
        }
    }

    @JvmStatic
    fun obtainFloatArray(size: Int = 2): FloatArray {
        return if (floatArrayPool.isEmpty()) {
            FloatArray(size) { 0f }
        } else {
            var obj: FloatArray? = null
            for (index in floatArrayPool.size - 1 downTo 0) {
                val value = floatArrayPool[index]
                if (value.size == size) {
                    obj = value
                }
            }

            if (obj == null) {
                FloatArray(size) { 0f }
            } else {
                floatArrayPool.remove(obj)
                obj
            }
        }
    }

    @JvmStatic
    @Suppress("UNCHECKED_CAST")
    fun <T : Paint> obtainPaint(isTextPaint: Boolean = false): T {
        return if (paintPool.isEmpty()) {
            if (isTextPaint) {
                TextPaint(Paint.ANTI_ALIAS_FLAG) as T
            } else {
                Paint(Paint.ANTI_ALIAS_FLAG) as T
            }
        } else {
            var obj: Paint? = null
            for (index in paintPool.size - 1 downTo 0) {
                val value = paintPool[index]
                if (isTextPaint) {
                    if (value is TextPaint) {
                        obj = value
                    }
                } else {
                    obj = value
                }
            }

            if (obj == null) {
                if (isTextPaint) {
                    TextPaint(Paint.ANTI_ALIAS_FLAG) as T
                } else {
                    Paint(Paint.ANTI_ALIAS_FLAG) as T
                }
            } else {
                paintPool.remove(obj)
                obj as T
            }
        }
    }

    @JvmStatic
    fun recyclePath(path: Path) {
        path.reset()
        pathPool.add(path)
        recycle()
    }

    @JvmStatic
    fun recyclePathMeasure(pathMeasure: PathMeasure) {
        pathMeasure.setPath(null, false)
        pathMeasurePool.add(pathMeasure)
        recycle()
    }

    @JvmStatic
    fun recycleRectF(rectF: RectF) {
        rectF.setEmpty()
        rectFPool.add(rectF)
        recycle()
    }

    @JvmStatic
    fun recycleFloatArray(floatArray: FloatArray) {
        for (index in floatArray.indices) {
            floatArray[index] = 0f
        }
        floatArrayPool.add(floatArray)
        recycle()
    }

    @JvmStatic
    fun recyclePaint(paint: Paint) {
        paint.reset()
        paint.isAntiAlias = true
        paint.textAlign = Paint.Align.LEFT
        paint.style = Paint.Style.FILL
        paintPool.add(paint)
        recycle()
    }

    private fun recycle() {
        isRelease = false
    }

    internal fun release() {
        if (isRelease) {
            return
        }

        pathPool.clear()
        pathMeasurePool.clear()
        rectFPool.clear()
        floatArrayPool.clear()
        paintPool.clear()
        isRelease = true
    }
}